using System;
using System.Linq;
using System.Reflection;
using Omu.Encrypto;
using Uber.Core.Model;
using Uber.Core.Repository;
using Uber.Core.Service;
using log4net;

namespace Uber.Service
{
    public interface IBuyAwfService
    {
        long PurchaseAwf(string paypalTransactionId, string custom, int quantity, decimal amount);
        void ProcessPurchase(long id);
    }

    public class BuyAwfService : IBuyAwfService
    {
        private readonly IUniRepo u;
        private readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private IMailSender mailSender;
        public BuyAwfService(IUniRepo u, IMailSender mailSender)
        {
            this.u = u;
            this.mailSender = mailSender;
        }

        public long PurchaseAwf(string paypalTransactionId, string custom, int quantity, decimal amount)
        {
            var em = string.Format("purchase awf tid:{0} custom:{1} quantity:{2} amount:{3}",
                                    paypalTransactionId, custom, quantity, amount);
            logger.Info(em);
            try
            {
                if(u.Where<Purchase>(p => p.PaypalTransactionId == paypalTransactionId).Count() > 0)
                    throw new UberEx("this transaction is already registered");

                var userId = Convert.ToInt64(custom);

                var o = u.Create<Purchase>();

                o.ProductVersionId = 1;
                o.PaypalTransactionId = paypalTransactionId;
                o.AmountPayed = amount;
                o.Custom = custom;
                o.UserId = userId;
                o.Quantity = quantity;
                o.DateCreated = DateTime.UtcNow;
                o.IsProcessed = false;

                u.Add(o);
                u.Save();
                if (o.Id == 0) throw new UberEx("purchase wasn't saved");
                logger.Info("processing purchase");
                ProcessPurchase(o.Id);
                logger.Info("purchase processed");
                var user = u.Get<Account>(userId);
                if(user.HasMail)
                mailSender.SendEmailAsync("noreply@projectawesome.com",user.Mail,"your purchase has been processed","you may now login on projectawesome.com and download your purchases from your profile");
                return o.Id;
            }
            catch (Exception ex)
            {
                logger.Error(em, ex);
                throw;
            }
        }

        public void ProcessPurchase(long id)
        {
            var purchase = u.Get<Purchase>(id);

            for (var i = 0; i < purchase.Quantity; i++)
            {
                var l = new License
                            {
                                ProductVersionId = purchase.ProductVersionId,
                                PurchaseId = purchase.Id,
                                UserId = purchase.UserId,
                                Code = MakeCode(purchase, i),
                                DateOfIssue = DateTime.UtcNow
                            };
                l.Key = MakeKey(l.Code);
                u.Add(l);
            }
            purchase.IsProcessed = true;
            u.Save();
        }

        private string MakeCode(Purchase purchase, int i)
        {
            var s = SerialGenerator.Do();
            return string.Format("AWF{0}-{1}",purchase.UserId+i, s);
        }

        private string MakeKey(string code)
        {
            var h = new Hasher { SaltSize = 1 };
            return h.Encrypt(code);
        }
    }
}